package com.example.blog.module.config.filter;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.blog.module.entity.LoginUser;
import com.example.blog.module.entity.SysUser;
import com.example.blog.module.entity.VO.Result;
import com.example.blog.module.enums.ErrorCode;
import com.example.blog.module.mapper.SysUserMapper;
import com.example.blog.module.service.LoginService;
import com.example.blog.module.service.impl.LoginServiceImpl;
import com.example.blog.module.utils.BaseContent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;

/**
 * springsecurity 认证过滤器
 * @author 郑家莽
 */
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends GenericFilterBean {

    public JwtAuthenticationTokenFilter(@Lazy LoginService loginService,RedisTemplate redisTemplate) {
        this.loginService = loginService;
        this.redisTemplate = redisTemplate;
    }
    private final LoginService loginService;

    private final RedisTemplate redisTemplate;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        /**
         * Controller方法处理之前
         * 1. 需要判断 请求的接口路径 是否为 HandlerMethod (controller方法)
         * 2. 判断 token是否为空，如果为空 未登录
         * 3. 如果token 不为空，登录验证 loginService checkToken
         * 4. 如果认证成功 放行即可
         */
        String token = ((HttpServletRequest)request).getHeader("Authorization");

        log.info("=================request start===========================");
        String requestURI = ((HttpServletRequest)request).getRequestURI();
        log.info("request uri:{}",requestURI);
        log.info("request method:{}",((HttpServletRequest)request).getMethod());
        log.info("token:{}", token);
        log.info("=================request end===========================");


        if (Objects.equals(requestURI, "/register") || Objects.equals(requestURI, "/login")){
            filterChain.doFilter(request, response);
            return;
        }

        if(StringUtils.isBlank(token)){
            Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), "未登录");
            //设置浏览器识别返回的是json
            response.setContentType("application/json;charset=utf-8");
            //https://www.cnblogs.com/qlqwjy/p/7455706.html response.getWriter().print()
            //SON.toJSONString则是将对象转化为Json字符串
            response.getWriter().print(JSON.toJSONString(result));
            return;
        }

        SysUser sysUser = loginService.checkToken(token);
        if (sysUser == null){
            Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), "未登录");
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().print(JSON.toJSONString(result));
            return;
        }

        //是登录状态，放行
        //登录验证成功，放行
        BaseContent.put(sysUser);

        LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get("login:"+sysUser.getId());

        //将实现UserDetails（security自带）的loginUser类，存入SecurityContextHolder，security会通过存入SecurityContextHolder判断当前是否通过认证
        //当前SecurityContextHolder中存有 loginuser ，之后的过滤器中认证 当前请求是否通过认证

        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //放行
        filterChain.doFilter(request, response);
    }

}
